<?php
/*
 * description：快递100物流查询逻辑类
 * author：wh
 * email：
 * createTime：{2025/8/26} {19:30}
 */

namespace wanghua\general_utility_tools_php\kuaidi;

use wanghua\general_utility_tools_php\tool\Tools;

/**
 * 快递100物流查询逻辑类
 *
 * 官方文档: https://api.kuaidi100.com/
 * 授权信息查看: https://api.kuaidi100.com/manager/v2/myinfo/enterprise
 */
class Kuaidi100Service
{
    /**
     * 客户授权key
     * @var string
     */
    private string $key;

    /**
     * 查询公司编号
     * @var string
     */
    private string $customer;

    /**
     * API请求地址
     * @var string
     */
    private string $apiUrl = 'https://poll.kuaidi100.com/poll/query.do';
    
    /**
     * 智能识别接口地址
     * @var string
     */
    private string $autoNumUrl = 'http://www.kuaidi100.com/autonumber/auto';

    /**
     * 构造函数
     *
     * @param string $customer 查询公司编号
     * @param string $key 客户授权key
     */
    public function __construct(string $customer, string $key)
    {
        $this->customer = $customer;
        $this->key = $key;
    }

    /**
     * 查询快递物流信息
     *
     * @param string $com 快递公司编码（如：yunda、shentong、yuantong等）
     * @param string $num 快递单号
     * @param string $phone 手机号（可选，顺丰等部分快递需要）
     * @param string $from 出发地城市（可选）
     * @param string $to 目的地城市（可选）
     * @param int $resultv2 是否开启行政区域解析（0：关闭，1：开启）
     * @param int $show 返回格式（0：json，1：xml，2：html，3：text）
     * @param string $order 排序方式（desc：降序，asc：升序）
     *
     * @return array 返回格式：
     *               [
     *                 'code' => 200 成功 / 非200 失败,
     *                 'msg'  => '错误描述',
     *                 'data' => 查询结果数组
     *               ]
     */
    public function query(
        string $num,
        string $com,
        string $phone = '',
        string $from = '',
        string $to = '',
        int $resultv2 = 1,
        int $show = 0,
        string $order = 'desc'
    ): array {
        // 参数验证
        if (empty($com)) {
            return [
                'code' => 400,
                'msg'  => '快递公司编码不能为空',
                'data' => null
            ];
        }

        if (empty($num)) {
            return [
                'code' => 400,
                'msg'  => '快递单号不能为空',
                'data' => null
            ];
        }

        // 构建查询参数
        $param = [
            'com' => $com,
            'num' => $num,
            'phone' => $phone,
            'from' => $from,
            'to' => $to,
            'resultv2' => (string)$resultv2,
            'show' => (string)$show,
            'order' => $order
        ];

        // 构建请求数据
        $postData = [
            'customer' => $this->customer,
            'param' => json_encode($param, JSON_UNESCAPED_UNICODE)
        ];

        // 生成签名
        $sign = md5($postData['param'] . $this->key . $postData['customer']);
        $postData['sign'] = strtoupper($sign);
        
        // 调试信息：记录请求参数
        Tools::log_to_write_txt(['快递100请求参数：'=>$postData]);

        // 发送请求
        $response = $this->sendRequest($postData);
        
        // 调试信息：记录响应结果
        Tools::log_to_write_txt(['快递100响应结果: ' =>$response]);
        return $response;
    }
    
    /**
     * 智能识别快递公司（充值后才赠送）
     *
     * 根据快递单号自动识别快递公司信息
     *
     * @param string $num 快递单号
     * @return array 返回格式：
     *               [
     *                 'code' => 200 成功 / 非200 失败,
     *                 'msg'  => '错误描述',
     *                 'data' => 识别结果数组
     *               ]
     */
    public function autoNum(string $num): array
    {
        // 参数验证
        if (empty($num)) {
            return [
                'code' => 400,
                'msg'  => '快递单号不能为空',
                'data' => null
            ];
        }
        
        // 构建请求URL
        $url = $this->autoNumUrl . '?num=' . $num . '&key=' . $this->key;
        
        // 调试信息：记录请求参数
        Tools::log_to_write_txt(['快递100智能识别请求参数：'=>$url]);

        // 发送请求
        $response = $this->sendAutoNumRequest($url);
        
        // 调试信息：记录响应结果
        Tools::log_to_write_txt(['快递100智能识别响应结果: ' =>$response]);
        return $response;
    }

    /**
     * 发送HTTP请求
     *
     * @param array $postData 请求数据
     * @return array
     */
    private function sendRequest(array $postData): array
    {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $this->apiUrl,
            CURLOPT_POST => true,
            CURLOPT_HEADER => false,
            CURLOPT_POSTFIELDS => http_build_query($postData),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_USERAGENT => 'Kuaidi100Logic/1.0'
        ]);

        $result = curl_exec($ch);

        // 检查CURL错误
        if ($result === false) {
            $errno = curl_errno($ch);
            $error = curl_error($ch);
            curl_close($ch);
            return [
                'code' => 500,
                'msg'  => "CURL请求失败: {$error} (错误码: {$errno})",
                'data' => null
            ];
        }

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        // 检查HTTP状态码
        if ($httpCode !== 200) {
            return [
                'code' => 500,
                'msg'  => "HTTP请求失败，状态码: {$httpCode}",
                'data' => null
            ];
        }

        // 解析返回结果
        $data = json_decode($result, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return [
                'code' => 500,
                'msg'  => 'JSON解析失败: ' . json_last_error_msg(),
                'data' => null
            ];
        }

        // 统一返回格式：直接返回快递100的原始响应数据
        return [
            'code' => 200,
            'msg'  => 'ok',
            'data' => $data
        ];
    }
    
    /**
     * 发送智能识别HTTP请求
     *
     * @param string $url 请求URL
     * @return array
     */
    private function sendAutoNumRequest(string $url): array
    {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_HEADER => false,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_USERAGENT => 'Kuaidi100Logic/1.0'
        ]);

        $result = curl_exec($ch);

        // 检查CURL错误
        if ($result === false) {
            $errno = curl_errno($ch);
            $error = curl_error($ch);
            curl_close($ch);
            return [
                'code' => 500,
                'msg'  => "CURL请求失败: {$error} (错误码: {$errno})",
                'data' => null
            ];
        }

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        // 检查HTTP状态码
        if ($httpCode !== 200) {
            return [
                'code' => 500,
                'msg'  => "HTTP请求失败，状态码: {$httpCode}",
                'data' => null
            ];
        }

        // 解析返回结果
        $data = json_decode($result, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return [
                'code' => 500,
                'msg'  => 'JSON解析失败: ' . json_last_error_msg(),
                'data' => null
            ];
        }

        // 检查是否返回错误信息
        if (isset($data['returnCode']) && $data['returnCode'] !== '200') {
            return [
                'code' => (int)$data['returnCode'],
                'msg'  => $data['message'] ?? '请求失败',
                'data' => null
            ];
        }

        // 统一返回格式：直接返回快递100的原始响应数据
        return [
            'code' => 200,
            'msg'  => 'ok',
            'data' => $data
        ];
    }

    /**
     * 设置API地址（用于测试或使用其他环境）
     *
     * @param string $apiUrl
     */
    public function setApiUrl(string $apiUrl): void
    {
        $this->apiUrl = $apiUrl;
    }
    
    /**
     * 设置智能识别接口地址（用于测试或使用其他环境）
     *
     * @param string $autoNumUrl
     */
    public function setAutoNumUrl(string $autoNumUrl): void
    {
        $this->autoNumUrl = $autoNumUrl;
    }
}